package com.ruoyi.workflow.convert;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.camunda.bpm.engine.delegate.TaskListener;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.impl.BpmnModelConstants;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnDiagram;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnPlane;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnShape;
import org.camunda.bpm.model.bpmn.instance.dc.Bounds;
import org.camunda.bpm.model.bpmn.instance.di.Shape;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

/**
 * @author TD
 * @version 1.0
 * @date 2023/12/26
 */
@Slf4j
public class ConvertUtils {

    public static BpmnModelInstance covert(BpmnProcessModelDTO dto) {

        // 创建BPMN的定义元素（bpmn:definitions）
        BpmnModelInstance modelInstance = Bpmn.createEmptyModel(); // // 创建空的BPMN模型对象
        Definitions definitions = modelInstance.newInstance(Definitions.class);
        definitions.setTargetNamespace("http://www.omg.org/spec/BPMN/20100524/MODEL"); // 设置 targetNamespace
        definitions.getDomElement().registerNamespace("camunda", "http://camunda.org/schema/1.0/bpmn"); // 设置自定义命名空间
        modelInstance.setDefinitions(definitions); // 添加到模型对象中

        // 创建BPMN的流程元素（bpmn:process）
        Process process = modelInstance.newInstance(Process.class);
        process.setId("process_" + dto.getId()); // 设置ID
        process.setName(dto.getName());// 名称
        process.setAttributeValueNs(BpmnModelConstants.CAMUNDA_NS, "allowRevoked", dto.getAllowRevoked()); // 自定义属性
        definitions.addChildElement(process); // 添加到定义元素中

        // 节点处理
        List<BpmnNodeDTO> nodeList = dto.getNodeList();
        if (CollUtil.isEmpty(nodeList)) {
            throw new ServiceException("节点不能为空");
        }

        for (BpmnNodeDTO node : nodeList) {
            Integer type = node.getType();
            switch (NodeTypeEnum.toType(type)) {
                case START_EVENT:
                    // 开始节点
                    createElement(process, node.getId(), StartEvent.class);
                    break;
                case USER_TASK:
                    // 用户任务
                    UserTask userTask = createElement(process, node.getId(), UserTask.class);
                    userTask.setName(node.getName());

                    // 设置签约人为上级领导表达式
                    Integer assigneeType = node.getAssigneeType();
                    if (AssigneeTypeEnum.SUPERIOR_LEADER.getCode().equals(assigneeType)) {
                        userTask.setCamundaAssignee("${superior_leader}");
                    }

                    // 添加任务监听器
                    // 多实例：    并行：   <bpmn:multiInstanceLoopCharacteristics />
                    //           串行：  <bpmn:multiInstanceLoopCharacteristics isSequential="true" />
                    // 用户任务签约 表达式{camunda:assignee="${assignee}}
                    //             <bpmn:multiInstanceLoopCharacteristics camunda:collection="assigneeList" camunda:elementVariable="assignee" isSequential="false">
                    //                <bpmn:completionCondition>${nrOfInstances == nrOfCompletedInstances}</bpmn:completionCondition>
                    //            </bpmn:multiInstanceLoopCharacteristics>
                    //     <bpmn:userTask id="Activity_18hu64e" name="">
                    //      <bpmn:extensionElements>
                    //        <camunda:executionListener delegateExpression="11111111" event="start" />
                    //      </bpmn:extensionElements>
                    //      <bpmn:incoming>Flow_0ut1lae</bpmn:incoming>
                    //      <bpmn:outgoing>Flow_1htqmj0</bpmn:outgoing>
                    //      <bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="list" camunda:elementVariable="index">
                    //        <bpmn:completionCondition xsi:type="bpmn:tFormalExpression">con</bpmn:completionCondition>
                    //      </bpmn:multiInstanceLoopCharacteristics>
                    //    </bpmn:userTask>
                    ExtensionElements extensionElements = modelInstance.newInstance(ExtensionElements.class);
                    ModelElementInstance taskListener = extensionElements.addExtensionElement(BpmnModelConstants.CAMUNDA_NS, "taskListener");
                    taskListener.setAttributeValueNs(BpmnModelConstants.CAMUNDA_NS, "class", MyTaskListener.class.getName());
                    taskListener.setAttributeValueNs(BpmnModelConstants.CAMUNDA_NS, "event", "create");
                    taskListener.setAttributeValueNs(BpmnModelConstants.CAMUNDA_NS, "id", "id1234556");
                    userTask.setExtensionElements(extensionElements);

                    break;
                case END_EVENT:
                    // 结束节点
                    createElement(process, node.getId(), EndEvent.class);
                    break;
                case SEQUENCE_FLOW:
                    // 序列流（连线，连线元素需要放在集合最后位置）
                    createSequenceFlow(modelInstance, process, node.getSequenceFrom(), node.getSequenceTo());
                    break;
                default:
                    throw new ServiceException("不支持当前节点类型");
            }
        }

        Bpmn.validateModel(modelInstance); // 检验

        String xmlString = Bpmn.convertToString(modelInstance);
        log.info("模型XML：{}", xmlString);

        return modelInstance;
    }

    /**
     * 创建 BPMN 元素对象
     *
     * @param parentElement 上级元素
     * @param id            元素ID
     * @param elementClass  元素类型
     * @param <T>           元素类型
     * @return 创建的BPMN 元素对象
     */
    protected static <T extends BpmnModelElementInstance> T createElement(BpmnModelElementInstance parentElement, String id, Class<T> elementClass) {
        T element = parentElement.getModelInstance().newInstance(elementClass); // 创建元素
        element.setAttributeValue("id", id, true);// 设置ID
        parentElement.addChildElement(element); // 添加到父元素下
        return element;
    }

    /**
     * 创建各个元素之间的序列流（连线）
     *
     * @param process 流程对象
     * @param fromId  开始元素
     * @param toId    结束元素
     * @return 序列流对象
     */
    public static SequenceFlow createSequenceFlow(BpmnModelInstance modelInstance, Process process, String fromId, String toId) {
        // 获取开始、结束节点
        FlowNode from = modelInstance.getModelElementById(fromId);
        FlowNode to = modelInstance.getModelElementById(toId);

        // 创建连线
        String identifier = from.getId() + "-" + to.getId();
        SequenceFlow sequenceFlow = createElement(process, identifier, SequenceFlow.class);

        // 设置开始、结束
        sequenceFlow.setTarget(to);
        sequenceFlow.setSource(from);

        // 节点添加输入输出
        from.getOutgoing().add(sequenceFlow);
        to.getIncoming().add(sequenceFlow);

        // 添加到流程中
        process.addChildElement(sequenceFlow);
        return sequenceFlow;
    }
}
